package com.atguigu.spzx.cloud.gateway.filter;

import com.alibaba.nacos.shaded.com.google.gson.JsonObject;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.List;

/*
    局部作用过滤器
            GatewayFilterFactory后的泛型必须指定，表示将来配置该filter时添加的参数 解析类型
 */
@Component
public class SpzxAuthGatewayFilterFactory1 implements GatewayFilterFactory<SpzxAuthGatewayFilterFactory1.ParamsConfig> {
    //用来指定如何解析过滤器后的参数: 当做List解析
    @Override
    public ShortcutType shortcutType() {
        return ShortcutType.GATHER_LIST;
    }
    //配置将参数列表如何转换
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("paths");
    }

    //生产GatewayFilter的方法：每一处配置都会新建一个对象
    @Override
    public GatewayFilter apply(ParamsConfig config) {

        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                //获取配置文件中需要校验token的路径列表
                System.out.println("paths : "+ config.getPaths());

                //编写过滤器的业务
                //             > 验证请求头中包含token的放行  否则拒绝请求 并响应一个Result对象的json字符串到响应体中
                String token = exchange.getRequest().getHeaders().getFirst("token");
                if(StringUtils.hasLength(token)){
                    //1、请求头中包含token ， 放行请求
                    System.out.println("token : "+ token);
                    return chain.filter(exchange);

                }
                //2、请求头中没有token，拒绝放行请求 返回 result{code:208 , message: '需要登录'}
                //2.1 获取响应对象
                ServerHttpResponse response = exchange.getResponse();
                //2.2 构建响应报文
                // 响应报文状态码
                response.setStatusCode(HttpStatus.OK);
                response.getHeaders().add("content-type" , MediaType.APPLICATION_JSON_UTF8_VALUE);
                //响应体：
                // - 先创建一个result的json字符串
                JsonObject json = new JsonObject();
                json.addProperty("code",208);
                json.addProperty("message","需要登录");
                String resultJsonStr = json.toString();
                // - 将json写入到响应体中
                DataBuffer data = null;
                try {
                    data = response.bufferFactory().wrap(resultJsonStr.getBytes("UTF-8"));
                } catch (UnsupportedEncodingException e) {
                    throw new RuntimeException(e);
                }
                //2.3 使用自己构建的响应报文响应
                return response.writeWith(Mono.just(data));
            }
        };
    }

    //提供解析过滤器参数的类型
    @Override
    public Class<ParamsConfig> getConfigClass() {
        return ParamsConfig.class;
    }
    //配置当前filter的名称
    @Override
    public String name() {
        return "Pangju";
    }

    //表示解析自定义filter配置参数的类
    static class ParamsConfig{
        private List<String> paths;//用来接收参数列表的集合

        public List<String> getPaths() {
            return paths;
        }

        public void setPaths(List<String> paths) {
            this.paths = paths;
        }
    }
}
